package com.cangxuan.manage.aspect;

import com.cangxuan.manage.annotation.Check;
import com.cangxuan.manage.annotation.check.*;
import com.cangxuan.manage.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 针对 控制器 的切面
 */
@Slf4j
@Aspect
@Component
public class ControllerAspect {

    /**
     * 定义切入点
     */
    @Pointcut("execution(* com.cangxuan.manage.controller.*Controller.*(..))")
    void pointcut(){}

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("ControllerAspect 前置通知...方法名：" + method.getName());

        Object[] arguments = joinPoint.getArgs();           //参数对象数组，如：student、clazz等
        Parameter[] parameters = method.getParameters();    //参数属性描述对象集合，每个元素(parameter)包含的是对应参数的属性，如参数名、参数类型、有哪些注解等
        for (Parameter parameter : parameters) {
            Check check = parameter.getAnnotation(Check.class);
            if (check != null) {
                log.info(">>>>>>>>>>>>>>>>>>>找到有@Check的参数的了，\t"
                        + "参数名为："+ parameter.getName()
                        + "参数类型为："+ parameter.getType());

                Object object = null;
                for (Object argument : arguments) {
                    if (argument != null && argument.getClass() == parameter.getType()) {
                        object = argument;
                        break;
                    }
                }

                //获取当前参数的类对象
                Class clazz = parameter.getType();
                log.info("clazz:" + clazz);
                //根据类对象获取其所有字段
                Field[] fields = clazz.getDeclaredFields();
                Method[] methods = clazz.getMethods();

                log.debug("字段数：" + fields.length);

                for (Field field : fields) {
                    log.debug("字段名：" + field.getName());
                    Method getMethod = null;
                    for (Method m : methods) {
                        if (field.getType() == boolean.class) {
                            if (m.getName().equalsIgnoreCase("is" + field.getName())) {
                                getMethod = m;
                                break;
                            }
                        } else {
                            if (m.getName().equalsIgnoreCase("get" + field.getName())) {
                                getMethod = m;
                                break;
                            }
                        }
                    }
                    log.debug("当前字段对应的get方法：" + getMethod.getName());
                    Object value;
                    try {
                        value = getMethod.invoke(object);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }

                    //根据field获取作用其上的指定的NotNull注解
                    NotNull notNull = field.getAnnotation(NotNull.class);
                    if (notNull != null) {
                        //说明filed被作用了NotNull注解，接下来就要判断object的当前field字段的值是否为null
                        if (value == null) {
                            log.error("错误信息：" + notNull.message());
                            throw new ServiceException(400, notNull.message());
                        }
                    }
                    //根据field获取作用其上的指定的NotEmpty注解
                    NotEmpty notEmpty = field.getAnnotation(NotEmpty.class);
                    if (notEmpty != null) {
                        //说明filed被作用了NotEmpty注解，接下来就要判断object的当前field字段的值是否为空字段串
                        if (value == null || value.equals("")) {
                            log.error("错误信息：" + notEmpty.message());
                            throw new ServiceException(400, notEmpty.message());
                        }
                    }
                    //根据field获取作用其上的指定的Length注解
                    Length length = field.getAnnotation(Length.class);
                    if (length != null) {
                        //说明filed被作用了Length注解，接下来就要判断object的当前field字段的值的长度
                        if (value.toString().length() < length.size()) {
                            log.error("错误信息：" + length.message());
                            throw new ServiceException(400, length.message());
                        }
                    }
                    //根据field获取作用其上的指定的Min注解
                    Min min = field.getAnnotation(Min.class);
                    if (min != null) {
                        //说明filed被作用了Min注解，接下来就要判断object的当前field字段的值的最小值
                        if (Integer.parseInt(value.toString()) < min.value()) {
                            log.error("错误信息：" + min.message());
                            throw new ServiceException(400, min.message());
                        }
                    }
                    //根据field获取作用其上的指定的Min注解
                    Max max = field.getAnnotation(Max.class);
                    if (max != null) {
                        //说明filed被作用了Max注解，接下来就要判断object的当前field字段的值的最大值
                        if (Integer.parseInt(value.toString()) > max.value()) {
                            log.error("错误信息：" + max.message());
                            throw new ServiceException(400, max.message());
                        }
                    }
                }


            }
        }

    }

    /**
     * 后置返回结果通知
     * @param joinPoint
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("ControllerAspect 返回结果通知...方法名：" + method.getName() + "，返回结果是：" + result);
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After("pointcut()")
    public void after(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("ControllerAspect 后置通知...方法名：" + method.getName());
    }

    /**
     * 环绕通知
     * @param joinPoint
     */
//    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        /*
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("ControllerAspect 环绕前置通知....方法名：" + method.getName());
        Object[] arguments = joinPoint.getArgs();           //参数对象数组，如：student、clazz等
        Parameter[] parameters = method.getParameters();    //参数属性描述对象集合，每个元素(parameter)包含的是对应参数的属性，如参数名、参数类型、有哪些注解等
        for (Parameter parameter : parameters) {
            Check check = parameter.getAnnotation(Check.class);
            if (check != null) {
                log.info(">>>>>>>>>>>>>>>>>>>找到有@Check的参数的了，\t"
                        + "参数名为："+ parameter.getName()
                        + "参数类型为："+ parameter.getType());

                Object object = null;
                for (Object argument : arguments) {
                    if (argument != null && argument.getClass() == parameter.getType()) {
                        object = argument;
                        break;
                    }
                }

                //获取当前参数的类对象
                Class clazz = parameter.getType();
                log.info("clazz:" + clazz);
                //根据类对象获取其所有字段
                Field[] fields = clazz.getDeclaredFields();
                Method[] methods = clazz.getMethods();

                log.info("字段数：" + fields.length);

                for (Field field : fields) {
                    log.info("字段名：" + field.getName());
                    Method getMethod = null;
                    for (Method m : methods) {
                        if (m.getName().equalsIgnoreCase("get" + field.getName())) {
                            getMethod = m;
                            break;
                        }
                    }
                    log.info("当前字段对应的get方法：" + getMethod.getName());
                    Object value;
                    try {
                        value = getMethod.invoke(object);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }

                    //根据field获取作用其上的指定的NotNull注解
                    NotNull notNull = field.getAnnotation(NotNull.class);
                    if (notNull != null) {
                        //说明filed被作用了NotNull注解，接下来就要判断object的当前field字段的值是否为null
                        if (value == null) {
                            log.info("错误信息：" + notNull.message());
                            throw new ServiceException(notNull.message());
                        }
                    }
                    //根据field获取作用其上的指定的NotEmpty注解
                    NotEmpty notEmpty = field.getAnnotation(NotEmpty.class);
                    if (notEmpty != null) {
                        //说明filed被作用了NotEmpty注解，接下来就要判断object的当前field字段的值是否为空字段串
                        if (value == null || value.equals("")) {
                            log.info("错误信息：" + notEmpty.message());
                            throw new ServiceException(notEmpty.message());
                        }
                    }
                    //根据field获取作用其上的指定的Length注解
                    Length length = field.getAnnotation(Length.class);
                    if (length != null) {
                        //说明filed被作用了Length注解，接下来就要判断object的当前field字段的值的长度
                        if (value.toString().length() < length.size()) {
                            log.info("错误信息：" + length.message());
                            throw new ServiceException(length.message());
                        }
                    }
                    //根据field获取作用其上的指定的Min注解
                    Min min = field.getAnnotation(Min.class);
                    if (min != null) {
                        //说明filed被作用了Min注解，接下来就要判断object的当前field字段的值的最小值
                        if (Integer.parseInt(value.toString()) < min.value()) {
                            log.info("错误信息：" + min.message());
                            throw new ServiceException(min.message());
                        }
                    }
                    //根据field获取作用其上的指定的Min注解
                    Max max = field.getAnnotation(Max.class);
                    if (max != null) {
                        //说明filed被作用了Max注解，接下来就要判断object的当前field字段的值的最大值
                        if (Integer.parseInt(value.toString()) > max.value()) {
                            log.info("错误信息：" + max.message());
                            throw new ServiceException(max.message(), "historyBack", "返回上一个页面");
                        }
                    }
                }


            }
        }


        log.info("ControllerAspect 执行代理的原始方法，并返回方法");
        Object result = joinPoint.proceed();       //执行代理的原始方法，并返回方法结果

        log.info("ControllerAspect 环绕后置通知...." + result);
         */

    }

}
